import os
import requests
import pandas as pd
from PIL import Image
import io
from tkinter import Tk, filedialog, messagebox, Label, Button, Text, Scrollbar, END, LabelFrame, StringVar, Entry  # 添加Entry
from tkinter import ttk
from urllib.parse import urljoin
import json
import sys

class BatchImageUploader:
    def __init__(self, base_domain, token):
        self.base_domain = base_domain
        self.token = token

    def upload_image(self, file_path, log_text):
        """上传单张图片"""
        try:
            filename = os.path.basename(file_path)
            api_url = f"{self.base_domain}/plugin/adminapi/site/uploadImage.json"
            with open(file_path, 'rb') as f:
                response = requests.post(
                    api_url,
                    files={'image': f},
                    data={'token': self.token}
                )
            data = response.json()

            if data.get('result') == 1:
                full_url = urljoin(self.base_domain, data.get('url'))
                log_text.insert(END, f"{filename}\t{full_url}\n")
                return full_url, None
            else:
                error_msg = data.get('info', '未知错误')
                log_text.insert(END, f"{filename}\t上传失败\t{error_msg}\n")
                return None, error_msg
        except Exception as e:
            log_text.insert(END, f"{filename}\t上传失败\t{str(e)}\n")
            return None, str(e)

    def upload_images_from_folder(self, folder_path, log_text):
        """从文件夹上传图片"""
        success_folder = os.path.join(folder_path, "上传成功")
        if not os.path.exists(success_folder):
            os.makedirs(success_folder)  # 创建“上传成功”文件夹

        log_file_path = os.path.join(folder_path, "upload_log.txt")
        with open(log_file_path, 'a', encoding='utf-8') as log_file:
            log_text.insert(END, "开始从文件夹上传图片...\n")
            log_file.write("开始从文件夹上传图片...\n")
            for filename in os.listdir(folder_path):
                if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
                    file_path = os.path.join(folder_path, filename)
                    log_text.insert(END, f"图片{filename}开始上传...\n")
                    full_url, error_msg = self.upload_image(file_path, log_text)
                    if full_url:
                        log_file.write(f"{filename}\t{full_url}\n")

                        # 移动成功上传的文件到“上传成功”文件夹
                        new_file_path = os.path.join(success_folder, filename)
                        os.replace(file_path, new_file_path)
                        # log_text.insert(END, f"文件 {filename} 移动到 {success_folder}\n")
                    else:
                        log_file.write(f"{filename}\t上传失败\t{error_msg}\n")
            log_text.insert(END, "文件夹上传完成。\n")
            log_file.write("文件夹上传完成。\n")

    def download_and_upload_image(self, url, log_text):
        """下载并上传单张图片"""
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()  # 确保请求成功

            # 验证下载内容是否为有效图片
            img_data = response.content
            try:
                img = Image.open(io.BytesIO(img_data))
            except IOError:
                error_msg = "下载内容不是有效的图片文件"
                log_text.insert(END, f"{url}\t上传失败\t{error_msg}\n")
                return None, error_msg

            # 将图片保存到BytesIO对象
            img_byte_arr = io.BytesIO()
            img.save(img_byte_arr, format=img.format)
            img_byte_arr.seek(0)  # 重置文件指针到开头

            api_url = f"{self.base_domain}/plugin/adminapi/site/uploadImage.json"
            response = requests.post(
                api_url,
                files={'image': ('temp.jpg', img_byte_arr, 'image/jpeg')},  # 正确传递文件对象
                data={'token': self.token}
            )
            data = response.json()

            if data.get('result') == 1:
                full_url = urljoin(self.base_domain, data.get('url'))
                log_text.insert(END, f"{url}\t{full_url}\n")
                return full_url, None
            else:
                error_msg = data.get('info', '未知错误')
                log_text.insert(END, f"{url}\t上传失败\t{error_msg}\n")
                return None, error_msg
        except requests.exceptions.RequestException as e:
            log_text.insert(END, f"{url}\t上传失败\t{str(e)}\n")
            return None, str(e)
        except Exception as e:
            log_text.insert(END, f"{url}\t上传失败\t{str(e)}\n")
            return None, str(e)

    def upload_images_from_excel(self, excel_path, log_text):
        """从Excel文件上传图片"""
        log_text.insert(END, "开始从Excel文件上传图片...\n")
        df = pd.read_excel(excel_path, na_filter=False)  # na_filter=False 保留空字符串
        df['上传结果'] = df['上传结果'].astype(str)  # 将“上传结果”列转换为字符串类型，便于统一处理

        for index, row in df.iterrows():
            upload_result = row['上传结果'].strip()  # 获取并去除前后空白

            # 如果上传结果为"1"，则跳过
            if upload_result == "1":
                log_text.insert(END, f"跳过已上传图片: {row['下载地址']}\n")
                continue

            url = row['下载地址']
            log_text.insert(END, "开始上传图片...\n")
            full_url, error_msg = self.download_and_upload_image(url, log_text)

            if full_url:
                df.at[index, '文件地址'] = full_url
                df.at[index, '上传结果'] = 1  # 更新上传结果为1
                df.at[index, '错误信息'] = ''  # 清空错误信息
            else:
                df.at[index, '错误信息'] = error_msg  # 记录错误信息

        df.to_excel(excel_path, index=False)
        log_text.insert(END, "Excel文件上传完成。\n")


class BatchImageUploaderApp:
    def __init__(self, root):
        self.root = root
        self.root.title("批量上传图片")
        self.root.geometry("800x600")

        self.base_domain = ""
        self.token = ""
        self.selected_path = ""

        self.config_manager = ConfigManager()
        self.domains = self.config_manager.config["domains"]
        self.recent_domains = self.config_manager.config["recent_domains"]

        self._init_ui()

    def _init_ui(self):
        # 登录区域
        self.login_frame = LabelFrame(self.root, text="登录")
        self.login_frame.pack(pady=10, padx=10, fill="x")

        Label(self.login_frame, text="域名:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.domain_var = StringVar()
        self.combo_domain = ttk.Combobox(
            self.login_frame,
            textvariable=self.domain_var,
            values=self.recent_domains
        )
        self.combo_domain.grid(row=0, column=1, padx=5, pady=5, sticky="w")
        self.combo_domain.state(["readonly"])  # 设置为只读模式
        self.combo_domain.bind("<<ComboboxSelected>>", self._on_domain_selected)

        # 允许自由输入
        self.combo_domain.config(state="normal")

        Label(self.login_frame, text="用户名:").grid(row=1, column=0, padx=5, pady=5, sticky="e")
        self.entry_username = Entry(self.login_frame, width=50)
        self.entry_username.grid(row=1, column=1, padx=5, pady=5, sticky="w")

        Label(self.login_frame, text="密码:").grid(row=2, column=0, padx=5, pady=5, sticky="e")
        self.entry_password = Entry(self.login_frame, width=50, show="*")
        self.entry_password.grid(row=2, column=1, padx=5, pady=5, sticky="w")

        self.btn_login = Button(self.login_frame, text="登录", command=self.login)
        self.btn_login.grid(row=3, column=0, columnspan=2, pady=10)

        # 文件选择区域
        self.file_select_frame = LabelFrame(self.root, text="文件选择")
        self.file_select_frame.pack(pady=10, padx=10, fill="x")

        Label(self.file_select_frame, text="选择文件夹或文件:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.label_selected_path = Label(self.file_select_frame, text="", width=50)
        self.label_selected_path.grid(row=0, column=1, padx=5, pady=5, sticky="w")

        self.btn_folder = Button(self.file_select_frame, text="选择文件夹", command=self.select_folder)
        self.btn_folder.grid(row=1, column=0, padx=5, pady=5)

        self.btn_excel = Button(self.file_select_frame, text="选择Excel文件", command=self.select_excel)
        self.btn_excel.grid(row=1, column=1, padx=5, pady=5)

        self.btn_start_upload = Button(self.file_select_frame, text="开始上传", command=self.start_upload, state="disabled")
        self.btn_start_upload.grid(row=1, column=2, padx=5, pady=5)

        # 日志区
        self.log_frame = LabelFrame(self.root, text="日志")
        self.log_frame.pack(pady=10, padx=10, fill="both", expand=True)

        self.log_text = Text(self.log_frame, wrap="word")
        self.log_text.pack(side="left", fill="both", expand=True)

        self.log_scrollbar = Scrollbar(self.log_frame, command=self.log_text.yview)
        self.log_scrollbar.pack(side="right", fill="y")

        self.log_text.config(yscrollcommand=self.log_scrollbar.set)

    def _on_domain_selected(self, *args):
        """选择域名后自动填充用户名密码"""
        selected_domain = self.domain_var.get().strip()
        domain_config = next((d for d in self.domains if d["url"] == selected_domain), None)
        if domain_config and domain_config["save_credentials"]:
            self.entry_username.delete(0, END)
            self.entry_username.insert(0, domain_config["username"])
            self.entry_password.delete(0, END)
            self.entry_password.insert(0, domain_config["password"])
        else:
            self.entry_username.delete(0, END)
            self.entry_password.delete(0, END)

    def login(self):
        selected_domain = self.domain_var.get().strip()
        username = self.entry_username.get().strip()
        password = self.entry_password.get().strip()

        if not selected_domain:
            messagebox.showerror("错误", "域名不能为空！")
            return

        if not username or not password:
            messagebox.showerror("错误", "用户名和密码不能为空！")
            return

        self.base_domain = selected_domain
        self.token = self._perform_login(selected_domain, username, password)

        if self.token:
            self.btn_login.config(state="disabled")
            self.combo_domain.config(state="disabled")
            self.entry_username.config(state="disabled")
            self.entry_password.config(state="disabled")
            self.btn_folder.config(state="normal")
            self.btn_excel.config(state="normal")
            self.btn_start_upload.config(state="normal")
            self.log_text.insert(END, "登录成功。\n")
        else:
            messagebox.showerror("错误", "登录失败，请检查用户名和密码！")

    def _perform_login(self, domain, username, password):
        try:
            login_url = f"{domain}/plugin/adminapi/login.json"
            response = requests.post(
                login_url,
                data={"username": username, "password": password},
                timeout=10
            )
            response.raise_for_status()
            data = response.json()
            if data.get("result") == 1:
                return data["token"]
            else:
                self.log_text.insert(END, f"登录失败: {data.get('info', '未知错误')}\n")
                return None
        except requests.exceptions.RequestException as e:
            self.log_text.insert(END, f"网络错误: {str(e)}\n")
            return None
        except json.JSONDecodeError as e:
            self.log_text.insert(END, f"响应解析错误: {str(e)}\n")
            return None
        except Exception as e:
            self.log_text.insert(END, f"未知错误: {str(e)}\n")
            return None

    def select_folder(self):
        folder_path = filedialog.askdirectory(title="选择图片文件夹")
        if folder_path:
            self.selected_path = folder_path
            self.label_selected_path.config(text=folder_path)
            self.btn_start_upload.config(state="normal")

    def select_excel(self):
        excel_path = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel files", "*.xls *.xlsx")]
        )
        if excel_path:
            self.selected_path = excel_path
            self.label_selected_path.config(text=excel_path)
            self.btn_start_upload.config(state="normal")

    def start_upload(self):
        if not self.selected_path:
            messagebox.showerror("错误", "请选择文件夹或Excel文件！")
            return

        uploader = BatchImageUploader(self.base_domain, self.token)

        if os.path.isdir(self.selected_path):
            uploader.upload_images_from_folder(self.selected_path, self.log_text)
        elif os.path.isfile(self.selected_path):
            uploader.upload_images_from_excel(self.selected_path, self.log_text)
        else:
            messagebox.showerror("错误", "选择的路径无效！")

class ConfigManager:
    def __init__(self, file_path="config/login.json"):
        self.file_path = self._get_absolute_path(file_path)
        self._check_config_file()

        self.config = self._load_config()

    def _get_absolute_path(self, relative_path):
        if getattr(sys, 'frozen', False):
            # 打包后路径
            base_path = sys._MEIPASS
        else:
            # 开发环境路径（向上退一级到项目根目录）
            base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

        full_path = os.path.join(base_path, relative_path)
        print(f"[DEBUG] 最终配置文件路径: {full_path}")  # 调试用
        return os.path.normpath(full_path)  # 标准化路径

    def _check_config_file(self):
        if not os.path.exists(self.file_path):
            print(f"Error: Config file not found at {self.file_path}")
            sys.exit(1)

    def _load_config(self):
        if os.path.exists(self.file_path):
            with open(self.file_path, "r", encoding="utf-8") as f:
                return json.load(f)
        else:
            print(f"Error: Config file not found at {self.file_path}")
            return {"domains": [], "recent_domains": []}

    def save_config(self):
        with open(self.file_path, "w", encoding="utf-8") as f:
            json.dump(self.config, f, indent=2)

    def add_domain(self, domain, username="", password="", save_credentials=False):
        if domain in self.config["recent_domains"]:
            self.config["recent_domains"].remove(domain)
        self.config["recent_domains"].insert(0, domain)
        self.config["recent_domains"] = self.config["recent_domains"][:10]

        existing = next((d for d in self.config["domains"] if d["url"] == domain), None)
        if existing:
            if save_credentials:
                existing.update({"username": username, "password": password, "save_credentials": True})
        else:
            self.config["domains"].append({
                "url": domain,
                "username": username if save_credentials else "",
                "password": password if save_credentials else "",
                "save_credentials": save_credentials
            })
        self.save_config()

if __name__ == "__main__":
    root = Tk()
    app = BatchImageUploaderApp(root)
    root.mainloop()
